#include "threadx.h"

/****** thread ******/
typedef struct structThread {
    pthread_t thread;
} Thread;

long threadx_create(vz_thread_func pfunc, void* param, long* out_hThread)
{
    if (pfunc == 0 || out_hThread == 0)
        return -1;
    
    Thread* thread = (Thread*)malloc(sizeof(Thread));
    if (thread == 0)
        return -2;
    
	int iRet = pthread_create(&thread->thread, 0, pfunc, param);
    errno = iRet; //线程创建不会设置错误码，而是直接返回错误码
    
	if(iRet != 0) // 创建失败
    {
        free(thread);
        return -3;
	}
    else
    {
        *out_hThread = (long)thread;
        return 0;
    }
}

long threadx_cancel(long hThread, bool bForce)
{
    if (hThread == 0)
        return -1;

    if (bForce)
    {
        pthread_cancel(((Thread*)hThread)->thread);
    }
    else
    {
        pthread_join(((Thread*)hThread)->thread, 0);
    }
   
    return 0;
}

/****** mutex ******/
typedef struct structMutex {
    pthread_mutex_t mutex;
} Mutex;

long mutexx_init(long* out_hMutex)
{
    if (out_hMutex == 0)
        return -1;
    
    Mutex* mutex = (Mutex*)malloc(sizeof(Mutex));
    if (mutex == 0)
        return -2;
    
	pthread_mutexattr_t mutexAttr;
	pthread_mutexattr_init(&mutexAttr);
	pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE);
	pthread_mutex_init(&mutex->mutex, &mutexAttr);
	pthread_mutexattr_destroy(&mutexAttr);
    
    *out_hMutex = (long)mutex;
    
    return 0;
}

long mutexx_unit(long hMutex)
{
    if (hMutex == 0)
        return -1;

	pthread_mutex_destroy(&((Mutex*)hMutex)->mutex);
    
    return 0;
}

long mutexx_lock(long hMutex)
{
    if (hMutex == 0)
        return -1;

    pthread_mutex_lock(&((Mutex*)hMutex)->mutex);
    
    return 0;
}

long mutexx_unlock(long hMutex)
{
    if (hMutex == 0)
        return -1;

    pthread_mutex_unlock(&((Mutex*)hMutex)->mutex);
    
    return 0;
}

/****** event ******/
typedef struct structEvent {
    pthread_mutex_t mutex;
    pthread_cond_t  cond;
} Event;

void Gettimespec(struct timespec* ptimespec, int offset)
{
	struct timeval   now;
	struct timespec  *ptime = (struct timespec *)ptimespec;
    
	gettimeofday(&now, NULL);
	ptime->tv_sec = now.tv_sec;
    
	int tmp = now.tv_usec + offset * 1000; //tmp是us级别的
	ptime->tv_sec = ptime->tv_sec + (tmp/(1000 * 1000));
	ptime->tv_nsec = (tmp % (1000 * 1000)) * 1000;
}

long eventx_init(long* out_hEvent)
{
    if (out_hEvent == 0)
        return -1;
    
    Event* event = (Event*)malloc(sizeof(Event));
   
    pthread_mutex_init(&event->mutex, NULL);
	pthread_cond_init(&event->cond, NULL);
    
    *out_hEvent = (long)event;

    return 0;
}

long eventx_unit(long hEvent)
{
    if (hEvent == 0)
        return -1;
    
    Event* event = (Event*)hEvent;
    
    pthread_cond_destroy(&event->cond);
	pthread_mutex_destroy(&event->mutex);
    
    free(event);
    
    return 0;
}

long eventx_post(long hEvent)
{
    if (hEvent == 0)
        return -1;
    
    Event* event = (Event*)hEvent;
    
    pthread_cond_signal(&event->cond);
    
    return 0;
}

long eventx_wait(long hEvent, unsigned int dwMilliseconds)
{
    if (hEvent == 0)
        return -1;
    
    Event* event = (Event*)hEvent;
    int ret = 0;
    
    if(dwMilliseconds == INFINITE)
	{
		pthread_mutex_lock(&event->mutex);
        ret = pthread_cond_wait(&event->cond, &event->mutex);
		pthread_mutex_unlock(&event->mutex);
	}
	else
	{
		struct timespec ts;
		Gettimespec(&ts, dwMilliseconds);
		pthread_mutex_lock(&event->mutex);
		ret = pthread_cond_timedwait(&event->cond, &event->mutex, &ts);
		pthread_mutex_unlock(&event->mutex);
	}
    
    return ret; // 0, ETIMEDOUT or others
}